//
//  main.m
//  RoutingEvaluator
//
//  Created by Christopher Kemsley on 4/12/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "NodeInfo.hpp"
#import "LinkInfo.hpp"
#import "CostAlgorithm.hpp"
#import "Object.hpp"
#import "Analyzer.hpp"
#import "Exception.hpp"

using namespace Sim ;






struct Main
{
	PropertySet		arguments ;
	ObjectContext	rootContext ;
	
	Main (int argc, const char * argv[])
	:	arguments(argv,argc)
		{
		rootContext.open() ;
		
		arguments . setValueIfNotSet ( "referenceNode" , "1" ) ;
		arguments . setValueIfNotSet ( "maxRange" , "20" ) ;
		arguments . setValueIfNotSet ( "outputPath" , "./" ) ;
		}
	~Main () { rootContext.close() ; }
	
	
	
	std::string const	makePath	( PropertySet const& args , std::string const & format )
		{
		std::string		path ;
		
		static std::string const	_begin	( "{" ) ;
		static std::string const	_end	( "}" ) ;
		
		size_t	loc_start = 0 ;
		size_t	loc_end ;
		
		while (  std::string::npos  !=  (loc_end=format.find(_begin,loc_start))  )
			{
			path += format.substr(loc_start,loc_end-loc_start) ;
			loc_start = ++loc_end ; // skip the '{'
			
			loc_end = format . find ( _end , loc_start ) ;
			std::string key = format.substr(loc_start,loc_end-loc_start) ;
			args . getValue ( key , key ) ;
			loc_start = ++loc_end ; // skip the '}'
			path += key ;
			}
		
		return path ;
		}
	
	void	runWorker	( Analyzer* worker , std::string const& path , NodeInfoSet * nodes , LinkInfoSet * costs ) {
		Output				output		( path ) ;
		
		ObjectContext innerContext ;
		innerContext.open() ;
		worker -> analyze ( nodes , costs , arguments , output ) ;
		innerContext.close() ;
	} ;
	
	
	
	int	runCatchingAll ()
		{
		try
			{
			return runCatchingObjC() ;
			}
		CatchAndRethrow ( "Main" , "Exception occurred while running" , __FILE__,__LINE__ ) ;
		return -1 ;
		}
	
	int	runCatchingObjC ()
		{
		@try
			{
			return run() ;
			}
		@catch ( NSException * e )
			{
			NSString * domain = [e name] ;
			NSString * reason = [e reason] ;
			NSString * format = [NSString stringWithFormat:@"%@: %@",domain,reason] ;
			ThrowException ( "ObjC Exception" , [format cStringUsingEncoding:NSASCIIStringEncoding] , __FILE__,__LINE__ ) ;
			}
		}
	
	
	
	
	
	
	int	run ()
		{
		/* Get the nodes */
		
		std::string		nodeInfoPath( "default" ) ;
		arguments . getValue ( "nodeInfoPath" , nodeInfoPath ) ;
		
		NodeInfoSet	*	nodes ;
		
		if ( nodeInfoPath == "default" )
			nodes	=	NodeInfoSet :: createDefaultNodeSet() ;
		else
			nodes	=	NodeInfoSet :: createWithContentsOfFile ( nodeInfoPath ) ;
		
		
		/* Make the links with the cost algorithm */
		
		CostAlgorithm const&	algorithm	=	CostAlgorithm :: distanceSquaredCost() ;
		LinkInfoSet	*	costs	=	LinkInfoSet :: createSetWithNodes ( algorithm , nodes ) ;
		
		
		/* Get some other properties */
		
		std::string		outputPath	( "./{mode}" ) ;
		arguments . getValue ( "outputPath" , outputPath ) ;
		
		std::string		modes		( "all" ) ;
		arguments . getValue ( "mode" , modes ) ;
		
		
		
		
		
		
		if ( modes == "all" )
			{
			std::map<std::string,Analyzer*>::const_iterator	here	=	Analyzer::analyzers().begin() ;
			std::map<std::string,Analyzer*>::const_iterator	end		=	Analyzer::analyzers().end() ;
			
			while ( here != end )
				{
				std::string const&	name	=	(*here).first ;
				Analyzer*			worker	=	(*here++).second ;
				
				PropertySet			args		( arguments ) ;
				args . setValue ( "mode" , name ) ;
				
				std::string			path	=	makePath ( args , outputPath ) ;
				
				runWorker ( worker , path , nodes , costs ) ;
				}
			}
		else
			{
			Analyzer*			worker	=	Analyzer::analyzer(modes) ;
			
			std::string			path	=	makePath ( arguments , outputPath ) ;
			
			runWorker ( worker , path , nodes , costs ) ;
			}
		
		
		
		return 0 ;
		}
	
} ;









#ifdef IAIsARC

#define	AutoreleasePoolBegin	@autoreleasepool {
#define	AutoreleasePoolEnd		}

#else

#define	AutoreleasePoolBegin	NSAutoreleasePool * pool = [ [NSAutoreleasePool alloc] init ] ;
#define	AutoreleasePoolEnd		[pool drain] ;

#endif




int main(int argc, const char * argv[])
{
	AutoreleasePoolBegin
		try
			{
			Main m ( argc , argv ) ;
			return m.run() ;
			}
		catch ( Exception & e )
			{
			std::cout << "Exiting due to exception: " << e << "\n\n" ;
			return -1 ;
			}
	AutoreleasePoolEnd
}

